# Active Record Migrations
Introduction
Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. If you have ever had to tell a teammate to manually add a column to their local database schema after pulling in your changes from source control, you've faced the problem that database migrations solve.
Generating Migrations
You may use the
bin/rails generate migrationrails command to generate a database migration. The new migration will be placed in your **db/migrate**directory. Each migration filename contains a timestamp that allows Laravel to determine the order of the migrations:bin/rails generate migration AddPartNumberToProducts1This will create an appropriately named empty migration:
class AddPartNumberToProducts < ActiveRecord::Migration[7.0] def change end end1
2
3
4Rials will use the name of the migration to attempt to guess the name of the table and whether or not the migration will be creating a new table. If Rails is able to determine the table name from the migration name, Rails will pre-fill the generated migration file with the specified table. Otherwise, you may simply specify the table in the migration file manually.
If the migration name is of the form "AddColumnToTable" or "RemoveColumnFromTable" and is followed by a list of column names and types then a migration containing the appropriate
[add_column](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_column)and[remove_column](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_column)statements will be created.bin/rails generate migration AddPartNumberToProducts part_number:string1will generate
class AddPartNumberToProducts < ActiveRecord::Migration[7.0] def change add_column :products, :part_number, :string end end1
2
3
4
5Migration Structure
Sometimes we see the method name is
upanddownand sometimes we see the method name ischangein the migration file.class AddPartNumberToProducts < ActiveRecord::Migration[7.0] def change end end1
2
3
4You can also use the old style of migration using
upanddownmethods instead of thechangemethod. Theupmethod should describe the transformation you'd like to make to your schema, and thedownmethod of your migration should revert the transformations done by theupmethod.class ExampleMigration < ActiveRecord::Migration[7.0] def up create_table :distributors do |t| t.string :zipcode end end def down drop_table :distributors end end1
2
3
4
5
6
7
8
9
10
11Running Migration
To run all of your outstanding migrations, execute the
migrateArtisan command:bin/rails db:migrate1If you would like to see which migrations have run thus far, you may use the
migrate:statusrails command:bin/rails db:migrate:status1If you specify a target version, Active Record will run the required migrations (change, up, down) until it has reached the specified version. The version is the numerical prefix on the migration's filename. For example, to migrate to version 20080906120000 run:
bin/rails db:migrate VERSION=200809061200001If version 20080906120000 is greater than the current version (i.e., it is migrating upwards), this will run the
change(orup) method on all migrations up to and including 20080906120000, and will not execute any later migrations. If migrating downwards, this will run thedownmethod on all the migrations down to, but not including, 20080906120000.By default running
bin/rails db:migratewill run in thedevelopmentenvironment. To run migrations against another environment you can specify it using theRAILS_ENVenvironment variable while running the command. For example to run migrations against thetestenvironment you could run:bin/rails db:migrate RAILS_ENV=test1Rolling Back
bin/rails db:rollback bin/rails db:rollback STEP=3 #shortcut for doing a rollback and then migrating back up again. bin/rails db:migrate:redo STEP=31
2
3
4
5
6Table
Creating Table
create_table :products do |t| t.string :name end1
2
3which creates a
productstable with a column calledname.By default,
create_tablewill create a primary key calledid. You can change the name of the primary key with the:primary_keyoption or, if you don't want a primary key at all, you can pass the optionid: false. If you need to pass database specific options you can place an SQL fragment in the:optionsoption. For example:create_table :products, options: "ENGINE=BLACKHOLE" do |t| t.string :name, null: false end1
2
3will append
ENGINE=BLACKHOLEto the SQL statement used to create the table.An index can be created on the columns created within the
create_tableblock by passing true or an options hash to the:indexoption:create_table :users do |t| t.string :name, index: true t.string :email, index: { unique: true, name: 'unique_emails' } end1
2
3
4Creating a Join Table
create_join_table :products, :categories1which creates a
categories_productstable with two columns calledcategory_idandproduct_id. These columns have the option:nullset tofalseby default. This can be overridden by specifying the:column_optionsoption:create_join_table :products, :categories, column_options: { null: true }1By default, the name of the join table comes from the union of the first two arguments provided to create_join_table, in alphabetical order. To customize the name of the table, provide a
:table_nameoption:create_join_table :products, :categories, table_name: :categorization1creates a
categorizationtable.create_join_tablealso accepts a block, which you can use to add indices (which are not created by default) or additional columns:create_join_table :products, :categories do |t| t.index :product_id t.index :category_id end1
2
3
4Changing Table
A close cousin of
create_tableis[change_table](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_table), used for changing existing tables. It is used in a similar fashion tocreate_tablebut the object yielded to the block knows more tricks. For example:change_table :products do |t| t.remove :description, :name t.string :part_number t.index :part_number t.rename :upccode, :upc_code end1
2
3
4
5
6removes the
descriptionandnamecolumns, creates apart_numberstring column and adds an index on it. Finally it renames theupccodecolumn.Changing Columns
Like the
remove_columnandadd_columnRails provides the[change_column](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column)migration method.change_column :products, :part_number, :text1This changes the column
part_numberon products table to be a:textfield. Note thatchange_columncommand is irreversible.Besides
change_column,the[change_column_null](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column_null)and[change_column_default](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column_default)method are used specifically to change a not null constraint and default values of a column.change_column_null :products, :name, false change_column_default :products, :approved, from: true, to: false1
2This sets
:namefield on products to aNOT NULLcolumn and the default value of the:approvedfield from true to false.References
The
add_referencemethod allows the creation of an appropriately named column.add_reference :users, :role1This migration will create a
role_idcolumn in the users table. It creates an index for this column as well, unless explicitly told not with theindex: falseoption:add_reference :users, :role, index: false1The method
add_belongs_tois an alias ofadd_reference.add_belongs_to :taggings, :taggable, polymorphic: true1The polymorphic option will create two columns on the taggings table which can be used for polymorphic associations:
taggable_typeandtaggable_id.A foreign key can be created with the
foreign_keyoption.add_reference :users, :role, foreign_key: true1References can also be removed:
remove_reference :products, :user, foreign_key: true, index: false1When Helpers aren't Enough
If the helpers provided by Active Record aren't enough you can use the
[execute](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-execute)method to execute arbitrary SQL:Product.connection.execute("UPDATE products SET price = 'free' WHERE 1=1")1